#!/bin/env bash
#########################################################################################################
# ██╗   ██╗ ██████╗ ██╗██████╗     ██╗███╗   ██╗███████╗████████╗ █████╗ ██╗     ██╗     ███████╗██████╗
# ██║   ██║██╔═══██╗██║██╔══██╗    ██║████╗  ██║██╔════╝╚══██╔══╝██╔══██╗██║     ██║     ██╔════╝██╔══██╗
# ██║   ██║██║   ██║██║██║  ██║    ██║██╔██╗ ██║███████╗   ██║   ███████║██║     ██║     █████╗  ██████╔╝
# ╚██╗ ██╔╝██║   ██║██║██║  ██║    ██║██║╚██╗██║╚════██║   ██║   ██╔══██║██║     ██║     ██╔══╝  ██╔══██╗
#  ╚████╔╝ ╚██████╔╝██║██████╔╝    ██║██║ ╚████║███████║   ██║   ██║  ██║███████╗███████╗███████╗██║  ██║
#   ╚═══╝   ╚═════╝ ╚═╝╚═════╝     ╚═╝╚═╝  ╚═══╝╚══════╝   ╚═╝   ╚═╝  ╚═╝╚══════╝╚══════╝╚══════╝╚═╝  ╚═╝
#########################################################################################################
# Writen: Bzz
# Link: https://notabug.org/bzz/void_installer/src/main/void_install.sh
# License: BSD
# About: Script for installing Void Linux. Support LUKS, EFI(no GRUB).
# Dependencies: xtools
# Information:
#			[-]=waiting
#			[+]=successful
#			[!]=warning
#			[*]=info
#			[?]=aksing
#########################################################################################################

## Colors
cl_red=$'\e[31m'
cl_green=$'\e[32m'
cl_yellow=$'\e[33m'
cl_blue=$'\e[34m'
cl_pink=$'\e[35m'
cl_normal=$'\e[0m'

## Environment
luks_name="crypt"
fs_type="ext4"
fs_type_boot="vfat"
sys_hostname="voidpc"
sys_language="en_US.UTF-8"
sys_locale="en_US.UTF-8 UTF-8"
sys_localtime="Europe/Uzhgorod"
sys_efi_options="rd.luks.allow-discards rd.driver.blacklist=nouveau loglevel=4"
admin_name="bzz"
user_name="user"
admin_groups="wheel,floppy,cdrom,optical,audio,video,kvm"
user_groups="audio,video"
repo_url="https://repo-default.voidlinux.org/current"
xbps_base_pkg="base-system cryptsetup efibootmgr"

clear

## Check is script running by root user
if [ "$(id -u)" != 0 ]; then
	printf "%s[!] Script needs to run as root%s\n" "${cl_red}" "${cl_normal}"
	exit 2
fi

# Check if the system is booted in UEFI mode
if [ ! -d /sys/firmware/efi ]; then
	printf "%s[!] System is booted in BIOS mode%s\n" "${cl_red}" "${cl_normal}"
	exit 2
fi

## Check if installed xgenfstab from xtools
if ! [ -x "$(command -v xgenfstab)" ]; then
	printf "%s[!] Program xtools is not installed!%s\n" "${cl_red}" "${cl_normal}"
	exit 1
fi

printf "%s######################%s\n" "${cl_blue}" "${cl_normal}"
printf "%s# Install Void Linux #%s\n" "${cl_blue}" "${cl_normal}"
printf "%s######################%s\n" "${cl_blue}" "${cl_normal}"

printf "%s===================%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Select disk ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s===================%s\n" "${cl_pink}" "${cl_normal}"

## Prompt user to select disk for installation
_root=$(df --output=source / | sed 1d | grep "/dev")
if [ $? -eq 0 ]; then
    run_dev=$(lsblk -psln -o NAME "$(df --output=source / | sed 1d | grep /dev)" | tail -n1)
else
    run_dev="/dev/loop"
fi

PS3="[?] Select disk for installation: "
select _ln in $(lsblk -pdno NAME,SIZE | sed 's/ \+/:/g' | grep -v "${run_dev}"); do
	if [ -z "${_ln}" ]; then
		printf "%s[!] Wrong selection%s\n" "${cl_red}" "${cl_normal}"
		exit 1
	fi
	printf "%s[+] Selected disk: <%s>%s\n" "${cl_yellow}" "${_ln}" "${cl_normal}"
	inst_dev=$(echo "${_ln}" | cut -d':' -f1)
	break
done

## Unmount all filesystem in /mnt folder
if grep -q " /mnt " /proc/mounts; then
	if ! umount -qR /mnt; then
		printf "%s[!] Erorr unmounting folder /mnt %s\n" "${cl_red}" "${cl_normal}"
		exit 1
	fi
fi

## Check if LUKS is open
_name=$(lsblk -nlo NAME,TYPE "${inst_dev}" | grep "crypt$" | awk '{ print$1}')
if [ -n "${_name}" ]; then
	if cryptsetup status "${_name}" | grep -q "is active"; then
		cryptsetup close "${_name}"
	fi
fi

## Check if luks_name is open
	if cryptsetup status "${luks_name}" | grep -q "is active"; then
		printf "%s[!] LUKS volume <%s> is active%s\n" "${cl_red}" "${luks_name}" "${cl_normal}"
		exit 1
	fi

## Check if installed device is mounted
for _dev in $(lsblk -pnlo NAME "${inst_dev}"); do
	if grep -q "${_dev}" /proc/mounts; then
		printf "%s[!] Device <%s> is mounted%s\n" "${cl_red}" "${_dev}" "${cl_normal}"
		exit 1
	fi
done

## Promt for script continuation
read -rp "[?] Install to device <${inst_dev}>: (y/n) " _key
if [ "${_key}" != "y" ]; then
	printf "%s[!] Aborted!%s\n" "${cl_red}" "${cl_normal}"
	exit 1
fi

## Wipe disk
wipefs -aqf "${inst_dev}" >/dev/null &&
	printf "%s[+] Wipe disk <%s>%s\n" "${cl_yellow}" "${inst_dev}" "${cl_normal}"

printf 'label: gpt\n, 1G, U, *\n, , L\n' | sfdisk -q "${inst_dev}" &&
	printf "%s[+] Create disklabel type <GPT> and partition%s\n" "${cl_yellow}" "${cl_normal}"

inst_dev_boot=$(lsblk -pnlo NAME "${inst_dev}" | sed -n 2p)
inst_dev_pool=$(lsblk -pnlo NAME "${inst_dev}" | sed -n 3p)

printf "%s========================%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Users and passwd ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s========================%s\n" "${cl_pink}" "${cl_normal}"

## Informations about users and passwords
read -rsp "[?] Password for user <root>: " root_pass
printf "\n"

read -rsp "[?] Password for user <${admin_name}>: " admin_pass
printf "\n"

printf "%s======================%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Encrypt volume ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s======================%s\n" "${cl_pink}" "${cl_normal}"

read -rsp "[?] Password for encrypting device: " luks_pass
printf "\n"
printf "%s[-] Encrypting partition, wait... %s" "${cl_yellow}" "${cl_normal}"

## Create LUKS
if echo "${luks_pass}" | cryptsetup -q luksFormat "${inst_dev_pool}"; then
	printf "%sOK!%s\n" "${cl_green}" "${cl_normal}"
else
	printf "%s[!] ERROR%s\n" "${cl_red}" "${cl_normal}"
	exit 1
fi

## Open encrypted partition
printf "%s[-] Opening volume to </dev/mapper/%s>... %s" "${cl_yellow}" "${luks_name}" "${cl_normal}"
if echo "${luks_pass}" | cryptsetup open "${inst_dev_pool}" "${luks_name}"; then
	printf "%sOK!%s\n" "${cl_green}" "${cl_normal}"
else
	printf "%s[!] ERROR%s\n" "${cl_red}" "${cl_normal}"
	exit 1
fi

printf "%s==========================%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Create FileSystems ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s==========================%s\n" "${cl_pink}" "${cl_normal}"

## Creating FS
printf "%s[-] Creating BOOT, wait... %s" "${cl_yellow}" "${cl_normal}"
mkfs.${fs_type_boot} -F 32 -n BOOT "${inst_dev_boot}" &&
	printf "%sOK!%s\n" "${cl_green}" "${cl_normal}"

printf "%s[-] Creating ROOT, wait... %s" "${cl_yellow}" "${cl_normal}"
mkfs.${fs_type} -qL ROOT /dev/mapper/${luks_name} &&
	printf "%sOK!%s\n" "${cl_green}" "${cl_normal}"

printf "%s=========================%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Mount FileSystems ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s=========================%s\n" "${cl_pink}" "${cl_normal}"

## Mount FS
mount /dev/mapper/${luks_name} /mnt &&
	printf "%s[+] Mount <root> to /mnt%s\n" "${cl_yellow}" "${cl_normal}"

mkdir -p /mnt/boot
mount "${inst_dev_boot}" /mnt/boot &&
	printf "%s[+] Mount <boot> to /mnt/boot%s\n" "${cl_yellow}" "${cl_normal}"

## Mount pseudo FS
for _fs in dev proc sys; do
	mkdir /mnt/${_fs}
	mount --rbind "/${_fs}" "/mnt/${_fs}"
	mount --make-rslave "/mnt/${_fs}"
	printf "%s[+] Mount /%s to /mnt/%s%s\n" "${cl_yellow}" "${_fs}" "${_fs}" "${cl_normal}"
done

printf "%s===============%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Install ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s===============%s\n" "${cl_pink}" "${cl_normal}"

printf "%s[-] Copying keys and packages...%s\n" "${cl_yellow}" "${cl_normal}"
mkdir -p /mnt/var/db/xbps/keys/
cp -v /var/db/xbps/keys/* /mnt/var/db/xbps/keys/
mkdir -p /mnt/var/cache/xbps
cp -v files/xbps/* /mnt/var/cache/xbps/

printf "%s[-] Installing base system, wait...%s\n" "${cl_yellow}" "${cl_normal}"
if xbps-install -SyR ${repo_url} -r /mnt ${xbps_base_pkg}; then
	printf "%sOK%s\n" "${cl_green}" "${cl_normal}"
else
	printf "%s[!] ERROR!!%s\n" "${cl_red}" "${cl_normal}"
	exit 1
fi

printf "%s==============%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Chroot ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s==============%s\n" "${cl_pink}" "${cl_normal}"

## Change ownership and permissions of root directory
chroot /mnt chown root:root /
chroot /mnt chmod 755 /

## Add and set passwords for users
printf "%s[+] Set password for user <root>%s\n" "${cl_yellow}" "${cl_normal}"
printf "%s\n%s" "${root_pass}" "${root_pass}" | passwd -R /mnt root

printf "%s[-] Adding user <%s>... %s" "${cl_yellow}" "${admin_name}" "${cl_normal}"
chroot /mnt useradd -p "${admin_pass}" -G "${admin_groups}" "${admin_name}" &&
	printf "%sOK!%s\n" "${cl_green}" "${cl_normal}"

printf "%s[-] Adding user <%s>... %s" "${cl_yellow}" "${user_name}" "${cl_normal}"
chroot /mnt useradd -p "${admin_pass}" -G "${user_groups}" "${user_name}" &&
	printf "%sOK!%s\n" "${cl_green}" "${cl_normal}"

## Set hostname, language/locale, timezone
echo "${sys_hostname}" > /mnt/etc/hostname
printf "%s[+] Set hostname <%s>%s\n" "${cl_yellow}" "${sys_hostname}" "${cl_normal}"

echo "LANG=${sys_language}" > /mnt/etc/locale.conf
printf "%s[+] Set language <%s>%s\n" "${cl_yellow}" "${sys_language}" "${cl_normal}"

ln -s /usr/share/zoneinfo/${sys_localtime} /etc/localtime
printf "%s[+] Set localtime <%s>%s\n" "${cl_yellow}" "${sys_localtime}" "${cl_normal}"

## libc-locales are only applicable for glibc installations
echo "${sys_locale}" >> /mnt/etc/default/libc-locales
printf "%s[-] Reconfiguring locale to <%s>, wait... %s" "${cl_yellow}" "${sys_locale}" "${cl_normal}"
chroot /mnt xbps-reconfigure -f glibc-locales >/dev/null &&
	printf "%sOK!%s\n" "${cl_green}" "${cl_normal}"

## Modify file /etc/fstab in chroot
#grep -E "(${inst_dev_boot}|/dev/mapper/${luks_name})" /proc/mounts |
#	awk '$2 == "/mnt/boot" { $2 = "/boot" }	$2 == "/mnt" { $2 = "/" } 1' >> /mnt/etc/fstab
xgenfstab -U /mnt > /mnt/etc/fstab
printf "%s[+] Update /etc/fstab%s\n" "${cl_yellow}" "${cl_normal}"

luks_uuid=$(lsblk -ndo UUID "${inst_dev_pool}")
root_uuid=$(lsblk -ndo UUID "/dev/mapper/${luks_name}")
cat <<EOF >> /mnt/etc/default/efibootmgr-kernel-hook
MODIFY_EFI_ENTRIES=1
OPTIONS="root=UUID=${root_uuid} rd.luks.uuid=${luks_uuid} ${sys_efi_options}"
DISK="${inst_dev}"
EOF

## Generate keyfile to automatically unlock the encrypted volume on boot.
dd bs=1 count=64 if=/dev/urandom of=/mnt/root/volume.key status=none
echo "${luks_pass}" | cryptsetup -q luksAddKey "${inst_dev_pool}" /mnt/root/volume.key

## Change the permissions to protect generated the keyfile
chroot /mnt chmod 000 /root/volume.key
chroot /mnt chmod g-rwx,o-rwx /root/volume.key
printf "%s\tUUID=%s\t/root/volume.key\tluks\n" "${luks_name}" "${luks_uuid}" >> \
	/mnt/etc/crypttab

## Configure for dracut
printf "install_items+=\" /root/volume.key /etc/crypttab \"\n" > \
	/mnt/etc/dracut.conf.d/10-crypt.conf

## Ensure an initramfs is generated
printf "%s[-] Reconfigure system, wait...%s\n" "${cl_yellow}" "${cl_normal}"
chroot /mnt xbps-reconfigure -fa
printf "%s[+] Done!%s\n" "${cl_yellow}" "${cl_normal}"

printf "%s=================%s\n" "${cl_pink}" "${cl_normal}"
printf "%s[*] Swap file ===%s\n" "${cl_pink}" "${cl_normal}"
printf "%s=================%s\n" "${cl_pink}" "${cl_normal}"

read -rp "[?] Use swap file 4Gb: (y/n) " _key
if [ "${_key}" == "y" ]; then

	## Adding swap file
	printf "%s[-] Creating swap file 4Gb, wait...%s" "${cl_yellow}" "${cl_normal}"
	if dd if=/dev/zero of=/mnt/swapfile bs=4096 count=1000000; then
		printf "%sOK%s\n" "${cl_green}" "${cl_normal}"
	else
		printf "%s[!] Error creating swap file%s\n" "${cl_red}" "${cl_normal}"
		exit 1
	fi

	## Set up a swap area
	printf "%s[-] Set up swap file, wait...%s" "${cl_yellow}" "${cl_normal}"
	if mkswap -q /mnt/swapfile; then
		printf "%sOK%s\n" "${cl_green}" "${cl_normal}"
	else
		printf "%s[!] Error mkswap file%s\n" "${cl_red}" "${cl_normal}"
		exit 1
	fi
	chmod 600 /mnt/swapfile

	## Adding swap file to /etc/fstab
	printf "/swapfile none swap sw 0 0\n" >> /mnt/etc/fstab
	printf "%s[+] Adding swap file to /etc/fstab%s\n" "${cl_yellow}" "${cl_normal}"
else
	printf "%s[+] Skipping configure swap file%s\n" "${cl_yellow}" "${cl_normal}"
fi


printf "%s#######################%s\n" "${cl_blue}" "${cl_normal}"
printf "%s# Finish install Void #%s\n" "${cl_blue}" "${cl_normal}"
printf "%s#######################%s\n" "${cl_blue}" "${cl_normal}"

printf "%s[-] Update wpa_supplicant.conf file...%s" "${cl_yellow}" "${cl_normal}"
if cp /etc/wpa_supplicant/wpa_supplicant.conf /mnt/etc/wpa_supplicant; then
	printf "%sOK%s\n" "${cl_green}" "${cl_normal}"
else
	printf "%s[!] Error updating%s\n" "${cl_red}" "${cl_normal}"
	exit 1
fi

printf "%s[-] EFI set bootorder...%s" "${cl_yellow}" "${cl_normal}"
efi_bootorder=$(efibootmgr | grep "Void Linux" | cut -f1 -d" " | cut -c 5-8)
if efibootmgr -o ${efi_bootorder}; then
	printf "%sOK%s\n" "${cl_green}" "${cl_normal}"
else
	printf "%s[!] Error%s\n" "${cl_red}" "${cl_normal}"
	exit 1
fi

read -rp "[?] Unmount newly created Void installation: (y/n) " _key
if [[ "${_key}" == "y" ]]; then
	umount -R /mnt                # Unmount root volume
	cryptsetup close ${luks_name} # Close LUKS encrypted partition
fi
